/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = ora_ttc7_tti_oer.c                                 */
/*  NOTE      =                                                    */
/*  DATE      = 2014/10/15 by songbb                               */
/*******************************************************************/

#include <stdio.h>
#include <memory.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>

#include "frstr.h"
#include "frmem.h"
#include "frcomm.h"
#include "frlog.h"

#include "conntrack.h"
#include "frct_comm.h"

#include "../../ora_core.h"
#include "../../comm/ora_comm.h"
#include "../../comm/ora_stmt.h"
#include "../../comm/ora_util.h"
#include "../ora_mar_engine.h"
#include "ora_ttc7_tti_oer.h"
#include "../../comm/ora_charset.h"


/*******************************************************************************
*  FUNC     :  解析TTIoer返回值
*  ARGS     :  *p_st_conn                           (ct信息)
*           :  *p_st_sess                           (Oracle私有的session)
*           :  *p_st_ora_packet                     (Oracle数据包)
*           :  i_sess_type                          (sess类型)
*  RTN      :  0                                    (FR_SUCC)
*              1                                    (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int ora_ttc7_tti_oer_unmarshal(Conntrack *p_st_conn
                            , L7session_ora *p_st_sess
                            , L7_ora_packet *p_st_ora_packet
                            , int i_sess_type
                            , Frhash_header *p_st_hash_report)
{
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_ora_private *p_st_session_private = (L7session_ora_private *) frct_get_session_private(p_st_session);
    L7_resp_ora *p_st_resp = p_st_session_private->p_st_resp;
    L7_ora_curr_session *p_st_curr_sess = p_st_session_private->p_st_curr_sess;
    Sql_statement *p_st_stmt = NULL;
    Sql_resultset *p_st_rs = NULL;
    char c_tmp = 0;
    short s_tmp = 0;
    int i_tmp = 0;
    long long ll_tmp = 0;
    long long ll_cur_row_number = 0LL;      // insert,update,delete时受影响的行数
    int i_ret_code = 0;                     // 返回的错误码
    int i_cursor = 0;                       // 游标
    char *p_error_msg = NULL;               // 返回的错误信息
    long long *p_ll_rows = NULL;
    unsigned int ui_error_msg_utf8_len = 0;
    int i_loop = 0;
    int i_max = 0;
    int i_ttc8_stmt_resp_oeraij_old = p_st_sess->i_ttc8_stmt_resp_oeraij;

    // TODO: ./apm -n -t 1 -d /mnt/hgfs/intellij14/apm/global/pcap/data_dev/oracle/aix/4_sqlplus_192.168.18.166_9.2.0.1.0_z_windows_2_192.168.18.228_11.2.0.1.0_w_sqe_off.pcap
    if (p_st_sess->i_use_oci == FR_YES && p_st_sess->s_tns_version >= 312 && ora_has_svr_compile_time_capability(p_st_sess, 15, 1) == FR_SUCC)
    {
        ORA_PRINT_DBG("oer skip eocs\n");
//        if (ora_mar_skip(p_st_ora_packet, 4) != FR_SUCC) 使用下面这种方式↓
//            goto error;
        if (ora_mar_skipUB4(p_st_sess, p_st_ora_packet) == FR_FAIL)             // eocs
            goto error;
    }

    if (p_st_sess->i_use_special_field == FR_YES && p_st_sess->i_send_typerep == FR_NO && p_st_sess->s_tns_version >= 313)
    {
        ORA_PRINT_DBG("oer skip endToEnd\n");
//        if (ora_mar_skip(p_st_ora_packet, 2) != FR_SUCC) 使用下面这种方式↓
//            goto error;
        if (ora_mar_skipSB2(p_st_sess, p_st_ora_packet) == FR_FAIL)
            goto error;
    }

    if (p_st_sess->i_use_special_field == FR_YES && p_st_sess->i_send_typerep == FR_NO)
    {
        ORA_PRINT_DBG("oer skip OCI1\n");
        if (ora_mar_skip(p_st_ora_packet, 1) != FR_SUCC)
            goto error;
    }

    if (ora_mar_unmarshalUB4(p_st_sess, p_st_ora_packet, &ll_cur_row_number) == FR_FAIL) // curRowNumber
        goto error;

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_ret_code) == FR_FAIL) // retCode
        goto error;
    // 解码错位的情况下可能存在retCode为负数的情况,排除掉
    if (i_ret_code < 0)
        goto error;

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_tmp) == FR_FAIL) // arrayElemWError
        goto error;

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_tmp) == FR_FAIL) // arrayElemErrno
        goto error;

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_cursor) == FR_FAIL) // currCursorID
        goto error;

    p_st_resp->l_response_code = i_ret_code;

    if (ora_mar_unmarshalSB2(p_st_sess, p_st_ora_packet, &s_tmp) == FR_FAIL) // errorPosition
        goto error;

    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) == FR_FAIL) // sqlType
        goto error;

    if (ora_mar_unmarshalSB1(p_st_sess, p_st_ora_packet, &c_tmp) == FR_FAIL) // oerFatal
        goto error;

    if (ora_mar_unmarshalSB1(p_st_sess, p_st_ora_packet, &c_tmp) == FR_FAIL) // flags
        goto error;

    if (ora_mar_unmarshalSB1(p_st_sess, p_st_ora_packet, &c_tmp) == FR_FAIL) // userCursorOpt
        goto error;

    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) == FR_FAIL) // upiParam
        goto error;

    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) == FR_FAIL) // warningFlag
        goto error;

    // TTIrid 区域代码 start

    // TTIti5 区域代码 start
    if (ora_mar_unmarshalUB4(p_st_sess, p_st_ora_packet, &ll_tmp) == FR_FAIL) // rba
        goto error;

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_tmp) == FR_FAIL) // partionID
        goto error;

    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) == FR_FAIL) // tableID
        goto error;
    // TTIti5 区域代码 end

    if (ora_mar_unmarshalUB4(p_st_sess, p_st_ora_packet, &ll_tmp) == FR_FAIL) // blockNumber
        goto error;

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_tmp) == FR_FAIL) // slotNumber
        goto error;

    // TTIrid 区域代码 end

    if (ora_mar_unmarshalSWORD(p_st_sess, p_st_ora_packet, &i_tmp) == FR_FAIL) // osError
        goto error;

    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) == FR_FAIL) // stmtNumber
        goto error;

    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) == FR_FAIL) // callNumber
        goto error;

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_tmp) == FR_FAIL) // pad1
        goto error;

    if (ora_mar_unmarshalUB4(p_st_sess, p_st_ora_packet, &ll_tmp) == FR_FAIL) // successIters
        goto error;

    if (p_st_sess->i_use_special_field == FR_YES)
    {
        if (p_st_sess->i_send_typerep == FR_NO)
        {
            if (ora_mar_skip(p_st_ora_packet, 40) != FR_SUCC)
                goto error;
            ORA_PRINT_NOTICE("oer end skip 40 bytes\n");
            if (p_st_sess->c_ttc_version >= 4)
            {
                if (ora_mar_skip(p_st_ora_packet, 40) != FR_SUCC)
                    goto error;
                ORA_PRINT_NOTICE("oer end skip 40 bytes\n");
                if (p_st_sess->c_ttc_version >= 7)
                {
                    if (ora_mar_skip(p_st_ora_packet, 8) != FR_SUCC)
                        goto error;
                    ORA_PRINT_NOTICE("oer end skip 8 bytes\n");
                }
            }
        }
        else
        {
            if (ora_mar_skip(p_st_ora_packet, 11) != FR_SUCC)
                goto error;
            ORA_PRINT_NOTICE("oer end skip 11 bytes\n");
        }
    }
    else
    {
        if (i_ttc8_stmt_resp_oeraij_old == APM_ORA_FLAG_UNSET)
        {
            if (bytebuff_remaining(p_st_ora_packet->p_st_packet) > 0)
            {
                if (ora_mar_peekUB1(p_st_ora_packet, &s_tmp) != FR_SUCC)
                    goto error;
                p_st_sess->i_ttc8_stmt_resp_oeraij = s_tmp == 0x00 ? FR_YES : FR_NO;
            }
            else
                p_st_sess->i_ttc8_stmt_resp_oeraij = FR_NO;

            ORA_PRINT_PARAM("i_ttc8_stmt_resp_oeraij:[%s]\n", FR_YESNO2STR(p_st_sess->i_ttc8_stmt_resp_oeraij));
        }

        if (p_st_sess->i_ttc8_stmt_resp_oeraij == FR_YES)
        {
            if (ora_mar_skipDALC(p_st_sess, p_st_ora_packet) != FR_SUCC) // arrayOfByte
                goto error;

            if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_max) == FR_FAIL) // i
                goto error;
            ORA_PRINT_INFO("unmarshaled i\n");
            for (i_loop = 0; i_loop < i_max; i_loop++)
            {
                if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_tmp) == FR_FAIL)
                    goto error;
            }

            if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_max) == FR_FAIL) // j
                goto error;
            ORA_PRINT_INFO("unmarshaled j\n");
            for (i_loop = 0; i_loop < i_max; i_loop++)
            {
                if (ora_mar_unmarshalUB4(p_st_sess, p_st_ora_packet, &ll_tmp) == FR_FAIL)
                    goto error;
            }

            if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_tmp) == FR_FAIL) // 跳过
                goto error;
        }
    }

    if (i_ret_code != 0)
    {
        if (ora_mar_unmarshalCLRforREFS(p_st_sess, p_st_ora_packet, &p_error_msg, &i_tmp) == FR_SUCC) // errorMsg
        {
            ora_free((void **) &(p_st_resp->p_response_codestring));
            ora_free((void **) &(p_st_resp->p_response_error_mesg));
            // 将错误信息转成utf8存储
            if (ora_str_to_utf8(p_st_sess, p_st_sess->s_cli_charset_out, p_error_msg, (unsigned int) i_tmp, &p_st_resp->p_response_error_mesg, &ui_error_msg_utf8_len) != FR_SUCC)
                goto error;
            if (ora_check_error_mesg(p_error_msg) != FR_SUCC)
            {
                ora_free((void **) &p_error_msg);
                goto error;
            }
            ora_util_extract_code_string(p_st_resp->p_response_error_mesg, &(p_st_resp->p_response_codestring));
            ORA_PRINT_DBG("code_string:[%s]\n", p_st_resp->p_response_codestring);
            ORA_PRINT_DBG("error_mesg:[%s]\n", p_st_resp->p_response_error_mesg);
            ora_free((void **) &p_error_msg);
        }
        else
            goto error;
    }

    if (i_sess_type == APM_ORA_SESS_IS_STMT)
    {
        if ((p_st_stmt = ora_get_stmt(p_st_conn, (long) i_cursor)) == NULL)
        {
            if (i_cursor == 0)
            {
                ORA_PRINT_EMERG("fatal to get stmt of cursor:[%d]\n", i_cursor);
                goto error;
            }
            ORA_PRINT_WARN("unexpected fail to get stmt of cursor:[%d]\n", i_cursor);
            if ((p_st_stmt = ora_get_new_stmt(p_st_conn)) == NULL)
            {
                // 新建一个游标为0的 Sql_statement
                if (ora_set_new_stmt(p_st_conn, &p_st_stmt) != FR_SUCC)
                    goto error;
            }
            // 将游标0更新为从服务端返回来的游标值
            if (frdb_add_statement(p_st_session_private->p_hash_stmt, i_cursor, p_st_stmt) != FR_SUCC)
                goto error;
            ORA_PRINT_DBG("add stmt of cursor 0 to hash_stmt and update to cursor:[%d]\n", i_cursor);
            p_st_session_private->p_st_req->p_st_stmt = NULL;
        }

        if ((p_st_rs = frdb_get_last_resultset(p_st_stmt)) == NULL)
            goto error;

        if (p_st_curr_sess->ui_batch_count != 0)
        {
            ORA_PRINT_TIMEVAL("set resp time st_timestamp_first", p_st_ora_packet->st_timestamp_first);
            ORA_PRINT_TIMEVAL("set resp time st_timestamp_last", p_st_ora_packet->st_timestamp_last);
            // 设置l4层信息和返回rows
            if (frdb_set_resultset_resp2(p_st_rs, (unsigned long) bytebuff_length(p_st_ora_packet->p_st_packet), p_st_curr_sess->ui_batch_count, (unsigned long *) p_st_curr_sess->p_ll_rows, &(p_st_ora_packet->st_timestamp_first), &(p_st_ora_packet->st_timestamp_last)) != FR_SUCC)
                goto error;
        }
        else
        {
            if ((p_ll_rows = (long long *) frmalloc(1 * sizeof(long long))) == NULL)
            {
                ORA_PRINT_EMERG("can not malloc memory\n");
                ORA_FRLOG_ERROR("can not malloc memory");
                goto error;
            }
            p_ll_rows[0] = ll_cur_row_number;
            ORA_PRINT_DBG("curRowNumber:[%lld]\n", ll_cur_row_number);

            ORA_PRINT_TIMEVAL("set resp time st_timestamp_first", p_st_ora_packet->st_timestamp_first);
            ORA_PRINT_TIMEVAL("set resp time st_timestamp_last", p_st_ora_packet->st_timestamp_last);
            // 设置l4层信息和返回rows
            if (frdb_set_resultset_resp2(p_st_rs, (unsigned long) bytebuff_length(p_st_ora_packet->p_st_packet), 1, (unsigned long *) p_ll_rows, &(p_st_ora_packet->st_timestamp_first), &(p_st_ora_packet->st_timestamp_last)) != FR_SUCC)
                goto error;
        }

        ora_free((void **) &p_ll_rows);
        ora_free((void **) &(p_st_curr_sess->p_ll_rows));
        p_st_curr_sess->ui_batch_count = 0;

        // select语句fetch的情况，如果一次不能取完，ret_code会是0
        if (p_st_stmt && p_st_stmt->p_sql && ora_is_sql_select(p_st_stmt->p_sql, strlen(p_st_stmt->p_sql)) == FR_SUCC && i_ret_code == 0)
        {
        }
        else if (p_st_hash_report)
        {
            if (ora_report_stmt_resp(p_st_conn, p_st_sess, p_st_stmt, p_st_hash_report, FR_YES) != FR_SUCC)
                goto error;
//            ORA_PRINT_INFO("delete cursor of [%ld] from p_hash_stmt\n", p_st_stmt->l_cursor_id);
//            frhash2_delLong(p_st_session_private->p_hash_stmt, p_st_stmt->l_cursor_id, frdb_statement_node_free);
//            ora_free_req_stmt(p_st_conn);
        }
    }

    return FR_SUCC;
error:
    p_st_sess->i_ttc8_stmt_resp_oeraij = i_ttc8_stmt_resp_oeraij_old;
    ora_free((void **) &p_ll_rows);
    ora_free((void **) &(p_st_curr_sess->p_ll_rows));
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  解析TTIoer warning返回值
*  ARGS     :  *p_st_conn                           (ct信息)
*           :  *p_st_sess                           (Oracle私有的session)
*           :  *p_st_ora_packet                     (Oracle数据包)
*  RTN      :  0                                    (FR_SUCC)
*              1                                    (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int ora_ttc7_tti_oer_unmarshal_warn(Conntrack *p_st_conn
                                    , L7session_ora *p_st_sess
                                    , L7_ora_packet *p_st_ora_packet)
{
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_ora_private *p_st_session_private = (L7session_ora_private *) frct_get_session_private(p_st_session);
    L7_resp_ora *p_st_resp = p_st_session_private->p_st_resp;

    int i_tmp = 0;
    int i_ret_code = 0;                     // 返回的错误码
    int i_warn_len = 0;

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_ret_code) == FR_FAIL) // retCode
        goto error;
    p_st_resp->l_response_code = i_ret_code;

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_warn_len) == FR_FAIL) // warnLength
        goto error;

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_tmp) == FR_FAIL) // warnFlag
        goto error;

    if (i_ret_code != 0 && i_warn_len != 0)
    {
        // TODO: 参照9i oracle/jdbc/ttc7/TTIoer.java:83解析
    }

    return FR_SUCC;
error:
    return FR_FAIL;
}

